package twi_project;

import java.awt.BorderLayout;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JFrame;

import jtools.files.filesystem.FileOperation;

import org.jdesktop.application.Application;

import prefuse.data.Graph;
import prefuse.data.Node;
import prefuse.util.GraphLib;
import twi.KeySearch;
import twi.OWLModel;
import twi.QueryManager;
import twi.query.Query;
import twi.query.SparqlQuery;
import twi.query.template2.Template;
import twi.query.template2.TemplateLibrary;
import twi.result.QueryResult;
import twi.user.User;
import twi.view.QueryMainPanel;
import twi.view.manipulation.CreateIndividualPanel;
import twi.view.manipulation.ModificationListener;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.RDFWriter;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.util.iterator.Filter;

public class TWI {

	private static TWI theInstance = new TWI();

	private TWI() {
	}

	public static TWI getInstance() {
		return theInstance;
	}

	private User currentUser;

	private File ontologieFile = null;

	private OWLModel ontologyModel;

	private QueryMainPanel queryPanel = null;

	private Query lastQuery;

	private boolean running = false;

	public void setOntologieFile(File file) {
		this.ontologieFile = file;
	}

	public void setUser(User user) {
		this.currentUser = user;
	}

	public void start() {
		if (this.ontologieFile == null) {
			JFrame jf = new OpenFrame();
			return;
		}
		readOntologie();
		if (!running){
			Application.launch(TWI_ProjectApp.class, null);
			running = true;
		}
	}

	private void readOntologie() {
		try {
			this.ontologyModel = OWLModel.readOWLFile(this.ontologieFile);
		} catch (IOException e) {
			e.printStackTrace();
			log("Could not load Ontologie, programm exit", true);
			System.exit(1);
		}
		log("Ontologie erfolgreich geladen", false);
//		IndividualAdding.testAdding();

	}

	public void log(String string, boolean b) {
		if (!b)
			System.out.println(string);
		else
			System.err.println(string);
	}

	public File getOntologieFile() {
		return this.ontologieFile;
	}

	Graph getPrefuseGraph(boolean classStrukture, boolean subclasses,
			boolean individuals, boolean objectProperties) {

		boolean[] mask = { classStrukture, subclasses, individuals,
				objectProperties };
		Graph g = new Graph(false);
		g.getNodeTable().addColumns(GraphLib.LABEL_SCHEMA);

		Iterator i = ontologyModel.listHierarchyRootClasses().filterDrop(
				new Filter() {
					public boolean accept(Object o) {
						return ((Resource) o).isAnon();
					}
				});

		Node root = g.addNode();
		root.setString(GraphLib.LABEL, this.ontologieFile.getName());
		while (i.hasNext()) {
			OntClass parentClass = (OntClass) i.next();
			showClass(parentClass, root, g, mask);
		}
		return g;
	}

	private void showClass(OntClass cl, Node parent, Graph g, boolean[] mask) {
		String name = cl.getLocalName();
		Node current = g.addNode();
		if (mask[0])
			current.setString(GraphLib.LABEL, name);
		if (mask[1])
			g.addEdge(parent, current);
		ExtendedIterator iter = cl.listSubClasses();
		while (iter.hasNext()) {
			showClass((OntClass) iter.next(), current, g, mask);
		}
		if (mask[2]) {
			iter = cl.listInstances();
			while (iter.hasNext())
				showClass((Individual) iter.next(), parent, g, mask);
		}
	}

	private void showClass(Individual cl, Node parent, Graph g, boolean[] mask) {
		String name = cl.getLocalName();
		Node current = g.addNode();
		if (mask[2])
			current.setString(GraphLib.LABEL, name);
		if (mask[1])
			g.addEdge(parent, current);
	}

	public ArrayList<String> searchKey(String text) {
		return KeySearch.searchKey(text, this.ontologyModel);
	}

	public OWLModel getOntologieModel() {
		return this.ontologyModel;
	}

	public void updateTemplates() {
		this.queryPanel.updateTemplates();
	}

	public void executeQuery(String query, boolean showResult) {
		executeQuery(new SparqlQuery(query, this.ontologyModel), showResult);
	}

	public void executeQuery(Query query, boolean showResult) {
		QueryResult result = QueryManager.executeQuery(query);
		if (result != null && showResult) {
			if (this.queryPanel == null)
				return;
			this.queryPanel.setResult(result);
			this.lastQuery = query;
		}
	}

	public void setQueryPanel(QueryMainPanel queryPanel) {
		this.queryPanel = queryPanel;
	}

	public boolean testQuery(String query) {
		QueryResult tres = QueryManager.executeQuery(new SparqlQuery(query,
				this.ontologyModel));
		if (tres instanceof QueryResult) {
			QueryResult res = (QueryResult) tres;
			if (res.getVariableNames().isEmpty())
				return false;
			if (res.getVariableList(res.getVariableNames().get(0)).isEmpty())
				return false;
			return true;
		}
		return false;
	}
	
	public void saveOntologie(String fileName, OntModel model, String namespaceString){
	 PrintWriter out = null;
	 try {
		out = new PrintWriter(new FileOutputStream(fileName,false));
		 RDFWriter writer = model.getWriter("RDF/XML-ABBREV") ;
		 writer.setProperty("xmlbase",namespaceString) ;
		 writer.write(model,out,namespaceString);
		 System.out.println("abspeichern fertig");
		 }
		 catch (FileNotFoundException ex) {
		 }
		 out.close() ;
	}

	public void saveTemplate(Template template, String name, String desc,
			boolean forAll) {
		TemplateLibrary.saveTemplate(template, name, desc, forAll, currentUser);
	}

	public User getCurrentUser() {
		return this.currentUser;
	}

	public void createNewInstance(String parentClassName, ModificationListener listener) {
		if (!this.currentUser.getPermissions().isCreateInstances()){
			ErrorDialog ed = new ErrorDialog(null, false, "You are not allowed to create new Instances, please ask your admin");
			ed.setVisible(true);
			return ;
		}
		OntClass parClass = this.ontologyModel.getOntClass(parentClassName);
		if (parClass == null){
			ErrorDialog ed = new ErrorDialog(null, false, "Sorry, but we can not find the class: "+parentClassName);
			ed.setVisible(true);
			return ;
		}
		JFrame jf = new JFrame();
		jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		jf.setLayout(new BorderLayout());
		jf.add(new CreateIndividualPanel(parClass,null, listener), BorderLayout.CENTER);
		jf.setVisible(true);
		jf.pack();
	}

	public void modifyInstance(String item, ModificationListener object) {
		if (!this.currentUser.getPermissions().isCreateInstances()){
			ErrorDialog ed = new ErrorDialog(null, false, "You are not allowed to create new Instances, please ask your admin");
			ed.setVisible(true);
			return ;
		}
		Individual indi = this.ontologyModel.getIndividual(item);
		JFrame jf = new JFrame();
		jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		jf.setLayout(new BorderLayout());
		jf.setSize(500, 500);
		jf.add(new CreateIndividualPanel(indi.getOntClass(), indi, object), BorderLayout.CENTER);
		jf.setVisible(true);
	}
	public void writeOntology() {
		try {
			FileOperation.copy(this.ontologieFile, new File(this.ontologieFile.getAbsolutePath()+".bak"), true);
			this.ontologieFile.delete();
			FileOutputStream f_out = new FileOutputStream(this.ontologieFile);
			Writer writer = new OutputStreamWriter(f_out, Charset.forName("ISO-8859-15"));
			this.ontologyModel.write(writer);
			writer.close();
			f_out.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

	public void repeatQuery() {
		if (this.lastQuery == null){
			this.lastQuery = new SparqlQuery("SELECT ?sub ?pre ?obj \n WHERE { ?sub ?pre ?obj. }", this.ontologyModel);
		}
		this.executeQuery(lastQuery, true);
	}


}
